package com.lzhl.buildjar.ui;

import com.lzhl.buildjar.App;
import com.lzhl.buildjar.dao.DaoFactory;
import com.lzhl.buildjar.dao.SchemeDao;
import com.lzhl.buildjar.po.Scheme;
import com.lzhl.buildjar.ui.support.*;
import com.lzhl.buildjar.util.FileUtils;
import com.lzhl.buildjar.util.ImageUtils;
import com.lzhl.buildjar.util.StringUtils;
import com.lzhl.buildjar.util.UIUtils;
import sun.awt.CausedFocusEvent;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.Element;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.List;

/**
 * @author 李柱良(@柱子的日月)
 * @date 2015/11/25
 */
public class ClassItemUI extends JPanel implements CmdListener {
    private SchemeDao schemeDao = (SchemeDao) DaoFactory.getDao("schemeDao");

    //右边
    private JFileField tfClassPath;
    private JButton btnClassPath;
    private JButton btnClassPathDefault;
    private JButton btnClassPathPosition;

    private JFileField tfOutput;
    private JButton btnOutput;
    private JButton btnOutputDefault;
    private JButton btnOutputPosition;

    private Box boxManifest;
    private JFileField tfManifest;
    private JButton btnManifest;
    private JButton btnManifestDefault;
    private JButton btnManifestPosition;

    private Box boxMainclass;
    private JTextField tfMainClass;

    private Box boxNote;
    private JCheckBox cbOpNote;
    private JScrollPane spNote;
    private JTextPane tpNote;
    private NoteUI noteUI;

    private JTable table;
    private FileTableModel model;
    private LinkedList<String> classItems = new LinkedList<String>();
    private JFileField tfEditor;

    private Scheme scheme;

    public ClassItemUI() {
        jblnit();
        init();
    }

    private void jblnit() {
        Container con = this;
        con.setLayout(new BorderLayout());
        //文件选择栏
        Box boxMain = Box.createVerticalBox();
        con.add(boxMain, BorderLayout.CENTER);

        //类路径选择
        Box boxClassPath = Box.createHorizontalBox();
        boxClassPath.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxClassPath.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
        boxMain.add(boxClassPath);
        JLabel lb = new JLabel("类  路径：");
        lb.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0));
        boxClassPath.add(lb);
        tfClassPath = new JFileField(new FileProvider(true));
        boxClassPath.add(tfClassPath);
        btnClassPath = new JButton(ImageUtils.getImageIcon("browser.png"));
        btnClassPath.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxClassPath.add(btnClassPath);
        btnClassPathPosition = new JButton(ImageUtils.getImageIcon("location.png"));
        btnClassPathPosition.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxClassPath.add(btnClassPathPosition);
        btnClassPathDefault = new JButton("默认");
        btnClassPathDefault.setMargin(new Insets(1, 4, 1, 2));
        boxClassPath.add(btnClassPathDefault);
        btnClassPath.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                checkClassPath();
                JFileChooser chooser = new JFileChooser();
                String classPath = tfClassPath.getText();
                if (classPath != null && classPath.trim().length() > 0) {
                    File dir = new File(classPath);
                    if (dir.isDirectory()) {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        } else {
                            chooser.setCurrentDirectory(dir);
                        }
                    } else {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        }
                    }
                }

                chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                int result = chooser.showOpenDialog(ClassItemUI.this);
                if (result == JFileChooser.APPROVE_OPTION) {
                    String filePath = chooser.getSelectedFile().getPath();
                    tfClassPath.setText(filePath);
                }
            }
        });
        btnClassPathDefault.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                tfClassPath.setText(Setting.getClasspath());
            }
        });
        btnClassPathPosition.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File classPathDir = checkClassPath();
                explorerFile(classPathDir, false);
            }
        });

        //输出路径选择
        Box boxOutput = Box.createHorizontalBox();
        boxOutput.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxOutput.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
        boxMain.add(boxOutput);
        lb = new JLabel("输出路径：");
        lb.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0));
        boxOutput.add(lb);
        tfOutput = new JFileField(new FileExProvider(new File("jar").getAbsolutePath()));
        boxOutput.add(tfOutput);
        btnOutput = new JButton(ImageUtils.getImageIcon("browser.png"));
        btnOutput.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxOutput.add(btnOutput);
        btnOutputPosition = new JButton(ImageUtils.getImageIcon("location.png"));
        btnOutputPosition.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxOutput.add(btnOutputPosition);
        btnOutputDefault = new JButton("默认");
        btnOutputDefault.setMargin(new Insets(1, 4, 1, 2));
        boxOutput.add(btnOutputDefault);
        btnOutput.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File defaultOutput = new File("jar");
                JFileChooser chooser = new JFileChooser();
                String output = tfOutput.getText();
                if (output != null && output.trim().length() > 0) {
                    File dir = new File(output);
                    if(!dir.getPath().equals(dir.getAbsolutePath())) {
                        dir = new File("jar" + File.separator + dir.getPath());
                    }
                    if (dir.isDirectory()) {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        } else {
                            chooser.setCurrentDirectory(dir);
                        }
                    } else {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        }
                    }
                }
                else {
                    chooser.setCurrentDirectory(defaultOutput);
                }

                int result = chooser.showOpenDialog(ClassItemUI.this);
                if (result == JFileChooser.APPROVE_OPTION) {
                    String filePath = chooser.getSelectedFile().getAbsolutePath();
                    String path = defaultOutput.getAbsolutePath() + File.separator;
                    if(filePath.startsWith(path)) {
                        tfOutput.setText(filePath.substring(path.length()));
                    }
                    else {
                        tfOutput.setText(filePath);
                    }
                }
            }
        });
        btnOutputDefault.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String path = "";
                if(scheme != null) {
                    String defaultOutputDir = getDefaultOutputDir();
                    path = defaultOutputDir + scheme.getName() + ".jar";
                }
                File defaultOutputFile = new File(path);
                tfOutput.setText(defaultOutputFile.getPath());
            }
        });
        btnOutputPosition.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File outputDir = new File("jar");

                String output = tfOutput.getText();
                //没有设置打开默认输出目录
                if (output == null || output.trim().length() == 0) {
                    explorerFile(outputDir, false);
                    return;
                }

                output = output.trim();
                File outputFile = new File(output);
                if(!outputFile.getPath().equals(outputFile.getAbsolutePath())) {
                    outputFile = new File("jar" + File.separator + outputFile.getPath());
                }
                if(outputFile.exists()) {
                    explorerFile(outputFile, true);
                }
                else {
                    File parent = outputFile.getParentFile();
                    if(parent != null) {
                        if(parent.isDirectory()) {
                            explorerFile(parent, false);
                        }
                        else {
                            JOptionPane.showMessageDialog(
                                    getTopLevelAncestor(), parent.getAbsolutePath() + "：目录不存在！");
                        }
                    }
                }
            }
        });

        //Manifest 选择
        boxManifest = Box.createHorizontalBox();
        boxManifest.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxManifest.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
        boxMain.add(boxManifest);
        lb = new JLabel("manifest：");
        lb.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0));
        boxManifest.add(lb);
        tfManifest = new JFileField(new FileExProvider(new File("jar").getAbsolutePath()));
        boxManifest.add(tfManifest);
        btnManifest = new JButton(ImageUtils.getImageIcon("browser.png"));
        btnManifest.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxManifest.add(btnManifest);
        btnManifestPosition = new JButton(ImageUtils.getImageIcon("location.png"));
        btnManifestPosition.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
        boxManifest.add(btnManifestPosition);
        btnManifestDefault = new JButton("默认");
        btnManifestDefault.setMargin(new Insets(1, 4, 1, 2));
        boxManifest.add(btnManifestDefault);
        btnManifest.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File defaultOutput = new File("jar");
                JFileChooser chooser = new JFileChooser();
                String classPath = tfManifest.getText();
                if (classPath != null && classPath.trim().length() > 0) {
                    File dir = new File(classPath);
                    if(!dir.getPath().equals(dir.getAbsolutePath())) {
                        dir = new File("jar" + File.separator + dir.getPath());
                    }
                    if (dir.isDirectory()) {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        } else {
                            chooser.setCurrentDirectory(dir);
                        }
                    } else {
                        File parent = dir.getParentFile();
                        if (parent != null) {
                            chooser.setCurrentDirectory(parent);
                        }
                    }
                }
                else {
                    chooser.setCurrentDirectory(defaultOutput);
                }

                int result = chooser.showOpenDialog(ClassItemUI.this);
                if (result == JFileChooser.APPROVE_OPTION) {
                    String filePath = chooser.getSelectedFile().getAbsolutePath();
                    String path = defaultOutput.getAbsolutePath() + File.separator;
                    if(filePath.startsWith(path)) {
                        tfManifest.setText(filePath.substring(path.length()));
                    }
                    else {
                        tfManifest.setText(filePath);
                    }
                }
            }
        });
        btnManifestDefault.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                tfManifest.setText("");
            }
        });
        btnManifestPosition.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                File manifestFile = checkManifest();
                if(manifestFile != null) {
                    explorerFile(manifestFile, true);
                }
                else {
                    JOptionPane.showMessageDialog(getTopLevelAncestor(), "manifest没有设置！");
                }
            }
        });

        //Mainclass
        boxMainclass = Box.createHorizontalBox();
        boxMainclass.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxMainclass.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
        boxMain.add(boxMainclass);
        lb = new JLabel("启动　类：");
        lb.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0));
        boxMainclass.add(lb);
        tfMainClass = new JTextField();
        boxMainclass.add(tfMainClass);

        boxNote = Box.createHorizontalBox();
        boxNote.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxNote.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
        boxMain.add(boxNote);
        lb = new JLabel("说　　明：");
        lb.setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 0));
        boxNote.add(lb);
        boxNote.add(Box.createHorizontalGlue());
        cbOpNote = new JCheckBox("打包说明");
        cbOpNote.setSelected(true);
        boxNote.add(cbOpNote);
        JButton btnTanchu = new JButton("弹出");
        btnTanchu.setMargin(new Insets (1, 4, 1, 2));
        boxNote.add(btnTanchu);
        tpNote = new JTextPane();
        spNote = new JScrollPane(tpNote);
        spNote.setAlignmentX(Component.LEFT_ALIGNMENT);
        spNote.setPreferredSize(new Dimension(200, 84));
        boxMain.add(spNote);
        btnTanchu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(noteUI == null) {
                    noteUI = new NoteUI((Frame)getTopLevelAncestor(), new OperationListener() {
                        @Override
                        public void operationPerformed(Object object) {
                            Map<String, Object> data = (Map<String, Object>) object;
                            String note = (String) data.get("note");
                            Integer position = (Integer) data.get("position");
                            tpNote.setText(note);
                            if (position >= 0 && position <= note.length()) {
                                tpNote.setCaretPosition(position);
                            }
                            tpNote.requestFocus();
                        }
                    });
                }
                noteUI.setNote(tpNote.getText(), tpNote.getCaretPosition());
                noteUI.setVisible(true);
            }
        });

        showAdvOption(Setting.isShowAdv());

        JScrollPane spFile = new JScrollPane();
        spFile.setAlignmentX(Component.LEFT_ALIGNMENT);
        boxMain.add(spFile);


        model = new FileTableModel();
        table = new JTable(model);
        class  MyTableAction extends AbstractAction {
            public MyTableAction() {
            }
            public MyTableAction(String name) {
                super(name);
            }

            public void actionPerformed(ActionEvent e) {
//                System.out.println(getValue(Action.NAME) + ":aaaaaaaaa");
            }
        }
//        for(Object key : table.getActionMap().getParent().keys()) {
//            table.getActionMap().put(key, new MyEnterAction(key.toString()));
//        }
        table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
        table.getActionMap().put("selectPreviousRow", new MyTableAction("selectPreviousRow"));
        table.getActionMap().put("selectNextRow", new MyTableAction("selectNextRow"));
        table.getActionMap().put("selectNextRowCell", new MyTableAction("selectNextRowCell"));

        table.setRowHeight(24);
        table.setSelectionBackground(new Color(235, 245, 255));
        table.setSelectionForeground(Color.BLACK);
        spFile.setViewportView(table);

//        DefaultTableCellHeaderRenderer headerRenderer = new DefaultTableCellHeaderRenderer();
//        headerRenderer.setHorizontalAlignment(JLabel.CENTER);
        PathRendererEditor pathRendererEditor = new PathRendererEditor();
        int colIndex = 0;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(26);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(26);
        table.getColumnModel().getColumn(colIndex).setMinWidth(26);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setCellRenderer(pathRendererEditor);
        table.getColumnModel().getColumn(colIndex).setCellEditor(pathRendererEditor);

        int wBtn = 20;
        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        ButtonRendererEditor btnRe = new ButtonRendererEditor(Cmd.LINE_BROWSER);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);
//      table.getTableHeader().getColumnModel().getColumn(collndex).setHeaderRenderer(headerRenderer);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_LOCATION);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);
//        table.getTableHeader().getColumnModel().getColumn(colIndex).setHeaderRenderer(headerRenderer);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_UP);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);
//        table.getTableHeader().getColumnModel().getColumn(colIndex).setHeaderRenderer(headerRenderer);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_DOWN);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_TOP);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);
//        table.getTableHeader().getColumnModel().getColumn(colIndex).setHeaderRenderer(headerRenderer);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_BOTTOM);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_DEL);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);

        colIndex++;
        table.getColumnModel().getColumn(colIndex).setPreferredWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMaxWidth(wBtn);
        table.getColumnModel().getColumn(colIndex).setMinWidth(wBtn);
        btnRe = new ButtonRendererEditor(Cmd.LINE_ADD);
        table.getColumnModel().getColumn(colIndex).setCellRenderer(btnRe);
        table.getColumnModel().getColumn(colIndex).setCellEditor(btnRe);
    }

    private void init() {
        App.registCmdListener(this);

        KeyListener keyListener = new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                if(e.getKeyCode() == KeyEvent.VK_DOWN) {
                    if(e.getSource() == tfClassPath && !tfClassPath.isSuggesting()) {
                        tfOutput.requestFocus();
                    }
                    else if(e.getSource() == tfOutput && !tfOutput.isSuggesting()) {
                        if(boxManifest.isVisible()) {
                            tfManifest.requestFocus();
                        }
                        else {
                            if(classItems.size() > 0) {
                                editRowAt(0);
                                showRowAt(0);
                            }
                        }
                    }
                    else if(e.getSource() == tfManifest && !tfManifest.isSuggesting()) {
                        tfMainClass.requestFocus();
                    }
                    else if(e.getSource() == tfMainClass) {
                        tpNote.requestFocus();
                    }
                    else if(e.getSource() == tpNote) {
                        if(classItems.size() > 0) {
                            int caretPosition =tpNote.getCaretPosition();
                            Element root = tpNote.getDocument().getDefaultRootElement();
                            //光标所在行
                            int lineNumber = root.getElementIndex( caretPosition ) + 1;
                            if(lineNumber == root.getElementCount()) {
                                editRowAt(0);
                                showRowAt(0);
                            }
                        }
                    }
                }
                else if(e.getKeyCode() == KeyEvent.VK_UP) {
                    if(e.getSource() == tfClassPath && !tfClassPath.isSuggesting()) {
                        if(classItems.size() > 0) {
                            editRowAt(classItems.size()-1);
                            showRowAt(classItems.size()-1);
                        }
                    }
                    else if(e.getSource() == tfOutput && !tfOutput.isSuggesting()) {
                        tfClassPath.requestFocus();
                    }
                    else if(e.getSource() == tfManifest && !tfManifest.isSuggesting()) {
                        tfOutput.requestFocus();
                    }
                    else if(e.getSource() == tfMainClass) {
                        tfManifest.requestFocus();
                    }
                    else if(e.getSource() == tpNote) {
                        int caretPosition =tpNote.getCaretPosition();
                        Element root = tpNote.getDocument().getDefaultRootElement();
                        //光标所在行
                        int lineNumber = root.getElementIndex( caretPosition ) + 1;
                        if(lineNumber == 1) {
                            tfMainClass.requestFocus();
                        }
                    }
                }
            }
        };
        tfClassPath.addKeyListener(keyListener);
        tfOutput.addKeyListener(keyListener);
        tfManifest.addKeyListener(keyListener);
        tfMainClass.addKeyListener(keyListener);
        tpNote.addKeyListener(keyListener);

        btnOutputPosition.addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                if(e instanceof CausedFocusEvent) {
                    CausedFocusEvent c = (CausedFocusEvent) e;
                    if (!boxManifest.isVisible()) {
                        if(c.getCause().equals(CausedFocusEvent.Cause.TRAVERSAL_FORWARD)) {
                            editRowAt(0);
                            showRowAt(0);
                        }
                    }
                }
            }
        });

        final Action selectPreviousColumnCell = table.getActionMap().getParent().get("selectPreviousColumnCell");
        if(selectPreviousColumnCell != null) {
            table.getActionMap().put("selectPreviousColumnCell", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    int rowIndex = table.getSelectedRow();
                    int colIndex = table.getSelectedColumn();
                    if(colIndex == 0 || colIndex == 1) {
                        if(rowIndex == 0) {
                            if(boxManifest.isVisible()) {
                                tpNote.requestFocus();
                            }
                            else {
                                btnOutputPosition.requestFocus();
                            }
                        }
                        else {
                            selectPreviousColumnCell.actionPerformed(e);
                            if(colIndex == 1) {
                                selectPreviousColumnCell.actionPerformed(e);
                            }
                        }
                    }
                    else if(colIndex == 2) {
                        editRowAt(rowIndex);
                    }
                    else {
                        selectPreviousColumnCell.actionPerformed(e);
                    }
                }
            });
        }

        final Action selectNextColumnCell = table.getActionMap().getParent().get("selectNextColumnCell");
        if(selectNextColumnCell != null) {
            table.getActionMap().put("selectNextColumnCell", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    int rowIndex = table.getSelectedRow();
                    int colIndex = table.getSelectedColumn();
                    if(colIndex == 0) {
                        editRowAt(rowIndex);
                    }
                    else if(colIndex == model.getColumnCount()-1) {
                        if(rowIndex == classItems.size()-1) {
                            App.fireCmd(Cmd.CATEGORY_FOCUS);
                        }
                        else {
                            editRowAt(rowIndex+1);
                        }
                    }
                    else {
                        selectNextColumnCell.actionPerformed(e);
                    }
                }
            });
        }
    }

    class FileTableModel extends AbstractTableModel {
        private String[] columnName = {
                "序", "文件", "", "", "", "", "", "", "", "",
        };

        public int getColumnCount() {
            return columnName.length;
        }

        public String getColumnName(int col) {
            return columnName[col];
        }

        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex > 0;
        }

        public int getRowCount() {
            return classItems.size();
        }

        public Object getValueAt(int row, int col) {
            switch (col) {
                case 0:
                    return row + 1;
                case 1:
                    return classItems.get(row);
                default:
                    return "";
            }
        }

        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if(columnIndex == 1) {
                String value = "";
                if(aValue != null) {
                    value = aValue.toString();
                }
                classItems.set(rowIndex, value);
            }
        }

        public synchronized void moveUp() {
            int index = table.getSelectedRow();
            if(index > 0 && index < classItems.size()) {
                String classItem = classItems.remove(index);
                if(classItem != null) {
                    classItems.add(index - 1, classItem);
                    super.fireTableDataChanged();
                    table.setRowSelectionInterval(index - 1, index - 1);
                    editRowAt(index - 1);
                    showRowAt(index - 1);
                }
            }
        }

        public synchronized void moveDown() {
            int index = table.getSelectedRow();
            if(index >= 0 && index < classItems.size() - 1) {
                String classItem = classItems.remove(index);
                if(classItem != null) {
                    classItems.add(index + 1, classItem);
                    super.fireTableDataChanged();
                    table.setRowSelectionInterval(index + 1, index + 1);
                    editRowAt(index + 1);
                    showRowAt(index + 1);
                }
            }
        }

        public synchronized void moveTop() {
            int index = table.getSelectedRow();
            if(index > 0 && index < classItems.size()) {
                String classItem = classItems.remove(index);
                if(classItem != null) {
                    classItems.addFirst(classItem);
                    super.fireTableDataChanged();
                    table.setRowSelectionInterval(0, 0);
                    editRowAt(0);
                    showRowAt(0);
                }
            }
        }

        public synchronized void moveBottom() {
            int index = table.getSelectedRow();
            if(index >= 0 && index < classItems.size() - 1) {
                String classItem = classItems.remove(index);
                if(classItem != null) {
                    classItems.addLast(classItem);
                    super.fireTableDataChanged();
                    table.setRowSelectionInterval(classItems.size() - 1, classItems.size() - 1);
                    editRowAt(classItems.size() - 1);
                    showRowAt(classItems.size() - 1);
                }
            }
        }
    }

    class PathRendererEditor extends AbstractCellEditor implements TableCellRenderer, TableCellEditor {
        private JTextField tfRender;

        public PathRendererEditor() {
            tfRender = new JTextField();
            tfEditor = new JFileField(new ClassProvider(){
                public String getClassPath() {
                    String classPath = tfClassPath.getText();
                    if(classPath == null) {
                        classPath = "";
                    }
                    return classPath.trim();
                }
            });
            tfEditor.setBackground(table.getSelectionBackground());
            tfEditor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0),"editUpRow");
            tfEditor.getActionMap().put("editUpRow", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    if(tfEditor.isSuggesting()) {
                        return;
                    }
                    int index = table.getSelectedRow();
                    if(index >= 0 && index < classItems.size()) {
                        if(index == 0) {
                            if(boxManifest.isVisible()) {
                                tpNote.requestFocus();
                            }
                            else {
                                tfOutput.requestFocus();
                            }
                        }
                        else {
                            editRowAt(index - 1);
                            Rectangle rect = table.getCellRect(index - 1, 0, true);
                            table.scrollRectToVisible(rect);
                        }
                    }
                }
            });
            tfEditor.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,0),"editDownRow");
            tfEditor.getActionMap().put("editDownRow", new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    if(tfEditor.isSuggesting()) {
                        return;
                    }
                    int index = table.getSelectedRow();
                    if(index >= 0 && index <= classItems.size() - 1) {
                        if(index == classItems.size() - 1) {
                            tfClassPath.requestFocus();
                        }
                        else {
                            editRowAt(index + 1);
                            Rectangle rect = table.getCellRect(index + 1, 0, true);
                            table.scrollRectToVisible(rect);
                        }
                    }
                }
            });
        }

        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if(value != null) {
                tfRender.setText(value.toString());
            }
            else {
                tfRender.setText("");
            }

            if(isSelected) {
                tfRender.setBackground(table.getSelectionBackground());
            }
            else {
                tfRender.setBackground(Color.WHITE);
            }

            return tfRender;
        }

        public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column) {
            tfEditor.setText((value == null) ? "" : value.toString());

            return tfEditor;
        }

        public Object getCellEditorValue() {
            return tfEditor.getText();
        }

        public boolean isCellEditable(EventObject e) {
            if(e instanceof MouseEvent) {
                return ((MouseEvent)e).getClickCount() >= 1;
            }
            return super.isCellEditable(e);
        }
    }

    class ButtonRendererEditor extends AbstractCellEditor
            implements TableCellRenderer, TableCellEditor, ActionListener {
        private JButton btnRender;
        private JButton btnEditor;

        public ButtonRendererEditor(Cmd cmd) {
            ImageIcon icom = ImageUtils.getImageIcon(cmd.getCode() + ".png");
            btnEditor = new JButton(icom);
            btnEditor.setActionCommand(cmd.getCode());
            btnEditor.putClientProperty("cmd", cmd);
            btnEditor.setMargin(new Insets(0, 0, 0, 0));
            btnEditor.addActionListener(this);
            btnEditor.setRequestFocusEnabled(false);
            btnEditor.setFocusable(false);

            btnRender = new JButton(icom);
            btnRender.setMargin(new Insets(0, 0, 0, 0));
        }

        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if(hasFocus) {
                btnRender.setForeground(table.getForeground());
                btnRender.setBackground(new Color(60, 179, 0));
            }
            else if(isSelected) {
                btnRender.setForeground(table.getSelectionForeground());
                btnRender.setBackground(table.getSelectionBackground());
            }
            else {
                btnRender.setForeground(table.getForeground());
                btnRender.setBackground(table.getBackground());
            }

            return btnRender;
        }

        public Component getTableCellEditorComponent(
                JTable table, Object value, boolean isSelected, int row, int column) {
            return btnEditor;
        }

        public Object getCellEditorValue() {
            return null;
        }

        public void actionPerformed(ActionEvent e) {
            JButton button = (JButton) e.getSource();
            Cmd cmd = (Cmd) button.getClientProperty("cmd");
            if(Cmd.LINE_BROWSER.equals(cmd)) {
                selectFile();
            }
            else if (Cmd.LINE_LOCATION.equals(cmd)) {
                lineLocation();
            }
            else if (Cmd.LINE_UP.equals(cmd)) {
                cmdLineUp();
            }
            else if(Cmd.LINE_DOWN.equals(cmd)) {
                cmdLineDown();
            }
            else if(Cmd.LINE_TOP.equals(cmd)) {
                cmdLineTop();
            }
            else if(Cmd.LINE_BOTTOM.equals(cmd)) {
                cmdLineBottom();
            }
            else if(Cmd.LINE_DEL.equals(cmd)) {
                delLine(table.getSelectedRow());
            }
            else if(Cmd.LINE_ADD.equals(cmd)) {
                addLine(table.getSelectedRow());
            }
        }
    }

    private void stopCellEditing() {
        if(table.isEditing()) {
            table.getCellEditor().stopCellEditing();
        }
    }

    private void editRowAt(final int rowIndex) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if(rowIndex >= 0 && rowIndex < classItems.size()) {
                    if(table.getSelectedRow() != rowIndex) {
                        table.setRowSelectionInterval(rowIndex, rowIndex);
                    }
                    if(table.getSelectedColumn() != 1) {
                        table.setColumnSelectionInterval(1, 1);
                    }
                    table.editCellAt(rowIndex, 1);
                    tfEditor.requestFocus();
                }
            }
        });
    }

    private void showRowAt(final int rowIndex) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                Rectangle rect = table.getCellRect(rowIndex, 1, true);
                table.scrollRectToVisible(rect);
            }
        });
    }

    private void editRowAt2(final int rowIndex) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if(rowIndex >= 0 && rowIndex < classItems.size()) {
                    if(table.getSelectedRow() != rowIndex) {
                        table.setRowSelectionInterval(rowIndex, rowIndex);
                    }
                    if(table.getSelectedColumn() != 1) {
                        table.setColumnSelectionInterval(1, 1);
                    }
                    tfEditor.putClientProperty("hasError", true);
                    table.editCellAt(rowIndex, 1);
                    tfEditor.requestFocus();
                }
            }
        });
    }

    private void addLine(final int index) {
        String classItem = null;
        if(index >= 0 && index < classItems.size()) {
            String rootPath = tfClassPath.getText();
            File rootFile = new File(rootPath);
            rootPath = rootFile.getAbsolutePath();
            classItem = classItems.get(index);
            File file = FileUtils.getFile(rootFile, classItem);
            if(file.exists()) {
                if(file.isDirectory()) {
                    classItem = file.getAbsolutePath();
                }
                else {
                    classItem = file.getParent();
                }
                if(classItem.length() >= (rootPath.length()+File.separator.length())) {
                    classItem = classItem.substring(rootPath.length()+File.separator.length());
                }
                else {
                    classItem = "";
                }
            }
            else {
                classItem = null;
            }
        }
        if(classItem == null) {
            classItem = "";
        }
        classItems.add(index + 1, classItem);
        model.fireTableRowsInserted(index + 1, index + 1);
        editRowAt(index + 1);
        showRowAt(index + 1);
    }

    private void delLine(int index) {
        if(index >= 0 && index < classItems.size()) {
            classItems.remove(index);
            model.fireTableRowsDeleted(index, index);
            if(index < classItems.size()) {
                editRowAt(index);
            }
            else if(index - 1 >= 0) {
                editRowAt(index - 1);
            }
        }
    }

    private void selectFile() {
        int index = table.getSelectedRow();
        //行不存在，不处理
        if(index < 0 || index >= classItems.size()) {
            return;
        }

        File classPathDir = checkClassPath();
        String classPath = classPathDir.getAbsolutePath();

        String currentPath = null;
        if(index >= 0 && index < classItems.size()) {
            String classItem = classItems.get(index);
            if(classItem != null) {
                classItem = classItem.trim();
                if(classItem.length() > 0) {
                    File classItemFile = FileUtils.getFile(classPathDir, classItem);
                    if(classItemFile.exists()) {
                        if(classItemFile.equals(classPathDir)) {
                            currentPath = classPath;
                        }
                        else {
                            currentPath = classItemFile.getParent();
                        }
                    }
                    else {
                        File p = classItemFile.getParentFile();
                        if(p.isDirectory()) {
                            currentPath = classItemFile.getParent();
                        }
                    }
                }
            }
        }

        if(currentPath == null) {
            currentPath = classPath;
        }

        JFileChooser chooser = new JFileChooser();
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        chooser.setCurrentDirectory(new File(currentPath));
        int result = chooser.showOpenDialog(this);
        if(result != JFileChooser.APPROVE_OPTION) {
            editRowAt(index);
            return;
        }

        File selectedfile = chooser.getSelectedFile();
        if(!selectedfile.exists()) {
            editRowAt(index);
            return;
        }

        String classItemPath = selectedfile.getAbsolutePath();
        classPath += File.separator;
        if(!classItemPath.startsWith(classPath)) {
            JOptionPane.showMessageDialog(getTopLevelAncestor(), "请选择类路径下面的文件或文件夹！");
            editRowAt(index);
            return;
        }
        String classItem = classItemPath.substring(classPath.length());
        classItems.set(index, classItem);
        model.fireTableRowsUpdated(index, index);
        editRowAt(index);
    }

    private void lineLocation() {
        int index = table.getSelectedRow();
        //行不存在，不处理
        if(index < 0 || index >= classItems.size()) {
            return;
        }

        File classPathDir = checkClassPath();
        String classItem = classItems.get(index);
        if(classItem != null && classItem.trim().length() > 0) {
            classItem = classItem.trim();
            File classItemFile = FileUtils.getFile(classPathDir, classItem);
            if(classItemFile.exists()) {
                if(classItemFile.isFile()) {
                    explorerFile(classItemFile, true);
                }
                else {
                    explorerFile(classItemFile, false);
                }
            }
            else {
//                File p = classItemFile.getParentFile();
//                if(p != null && p.isDirectory()) {
//                    explorerFile(p, false);
//                }
                JOptionPane.showMessageDialog(getTopLevelAncestor(),
                        "[" + classItemFile.getName() + "]包或类不存在！");
            }
        }
        else {
            explorerFile(classPathDir, false);
        }
    }

    public Object handleCmd(Cmd cmd, Object data) {
        if(Cmd.SCHEME_OPEN.equals(cmd)) {
            loadScheme((Scheme) data);
        }
        else if(Cmd.SCHEME_SAVE.equals(cmd)) {
            Boolean showMessage = (Boolean) data;
            if(showMessage == null) {
                showMessage = Boolean.TRUE;
            }
            saveScheme(showMessage);
        }
        else if(Cmd.SCHEME_SEND.equals(cmd)) {
            Scheme s = (Scheme) data;
            if(scheme != null && s != null) {
                scheme.setName(s.getName());
                saveScheme(false);
            }
        }
        else if(Cmd.SCHEME_REFRESH.equals(cmd)) {
            loadScheme(scheme);
        }
        else if (Cmd.SHOW_ADV.equals(cmd)) {
            showAdvOption((Boolean) data);

        }
        else if(Cmd.IS_EDITED.equals(cmd)) {
            return isEdited();
        }

        else if(Cmd.AUTO_FILL.equals(cmd)) {
            if(data instanceof AutoFill) {
                cmdAutoFill((AutoFill) data);
            }
        }
        else if(Cmd.TO_JAVA.equals(cmd)) {
            cmdToJava();
        }
        else if(Cmd.TO_CLASS.equals(cmd)) {
            cmdToClass();
        }

        //line
        else if(Cmd.LINE_UP.equals(cmd)) {
            cmdLineUp();
        }
        else if(Cmd.LINE_DOWN.equals(cmd)) {
            cmdLineDown();
        }
        else if(Cmd.LINE_TOP.equals(cmd)) {
            cmdLineTop();
        }
        else if(Cmd.LINE_BOTTOM.equals(cmd)) {
            cmdLineBottom();
        }
        else if(Cmd.LINE_ADD.equals(cmd)) {
            cmdLineAdd();
        }
        else if(Cmd.LINE_DEL.equals(cmd)) {
            cmdLineDel();
        }
        else if(Cmd.LINE_CLEAR.equals(cmd)) {
            cmdLineClear();
        }

        //build
        else if(Cmd.ADD_INNER.equals(cmd)) {
            addInner();
        }
        else if(Cmd.DEL_INNER.equals(cmd)) {
            delInner();
        }
        else if(Cmd.CLEAR_REPEAT.equals(cmd)) {
            clearRepeat();
        }
        else if(Cmd.CHECK_SCHEME.equals(cmd)) {
            checkScheme();
        }
        else if(Cmd.BUILD_JAR.equals(cmd)) {
            btnBuildActionPerformed();
        }

        else if(Cmd.SCHEME_FOCUS.equals(cmd)) {
            tfClassPath.requestFocus();
        }

        return null;
    }

    public void loadScheme(Scheme s) {
        stopCellEditing();

        tfClassPath.setText("");
        tfOutput.setText("");
        tfManifest.setText("");
        tfMainClass.setText("");
        cbOpNote.setSelected(true);
        tpNote.setText("");
        classItems.clear();
        if(s == null) {
            model.fireTableDataChanged();
            return;
        }

        scheme = schemeDao.getScheme(s.getId());
        tfClassPath.setText(scheme.getClasspath());
        tfOutput.setText(scheme.getOutput());
        tfManifest.setText(scheme.getManifest());
        tfMainClass.setText(scheme.getMainclass());
        cbOpNote.setSelected(scheme.isOpNote());
        tpNote.setText(scheme.getNote());
        classItems.addAll(scheme.getClassitems());

        model.fireTableDataChanged();
    }

    public void saveScheme(boolean showMessage) {
        if(scheme == null) {
            return;
        }
        storeScheme(scheme);
        schemeDao.saveScheme(scheme);
        if(showMessage) {
            JOptionPane.showMessageDialog(getTopLevelAncestor(), "保存成功。");
        }
    }

    private boolean isEdited() {
        if(scheme == null) {
            return false;
        }
        stopCellEditing();

        if(!StringUtils.equals(tfClassPath.getText(), scheme.getClasspath())) {
            return true;
        }
        if(!StringUtils.equals(tfOutput.getText(), scheme.getOutput())) {
            return true;
        }
        if(!StringUtils.equals(tfManifest.getText(), scheme.getManifest())) {
            return true;
        }
        if(!StringUtils.equals(tfMainClass.getText(), scheme.getMainclass())) {
            return true;
        }
        if(cbOpNote.isSelected() != scheme.isOpNote()) {
            return true;
        }
        if(!StringUtils.equals(tpNote.getText(), scheme.getNote())) {
            return true;
        }
        if(!StringUtils.equals(StringUtils.toString(classItems), StringUtils.toString(scheme.getClassitems()))) {
            return true;
        }

        return false;
    }

    private void storeScheme(Scheme scheme) {
        if(scheme == null) {
            return;
        }
        stopCellEditing();

        scheme.setClasspath(tfClassPath.getText());
        scheme.setOutput(tfOutput.getText());
        scheme.setManifest(tfManifest.getText());
        scheme.setMainclass(tfMainClass.getText());
        scheme.setOpNote(cbOpNote.isSelected());
        scheme.setNote(tpNote.getText());
        java.util.List<String> list = new ArrayList<String>(classItems.size());
        list.addAll(classItems);
        scheme.setClassitems(list);
    }

    private void cmdAutoFill(AutoFill autoFill) {
        stopCellEditing();

        if(autoFill.getClasspath() == null) {
            File classPathDir = checkClassPath();
            autoFill.setClasspath(classPathDir);
        }

        LinkedList<String> lastClasses = FileUtils.getLastClasses(autoFill);
        List<String> items = new ArrayList<String>();
        for(String lastClass : lastClasses) {
            if(!classItems.contains(lastClass)) {
                items.add(lastClass);
            }
        }
        if(items.size() > 0) {
            if(classItems.size() == 1
                    && (classItems.get(0) == null || classItems.get(0).trim().length() == 0)) {
                classItems.clear();
            }
            int firstRow = classItems.size();
            classItems.addAll(items);
            int lastRow = classItems.size()-1;
            model.fireTableRowsInserted(firstRow, lastRow);
            editRowAt(lastRow);
        }
    }

    private void cmdToJava() {
        if(classItems.size() <= 0) {
            return;
        }

        stopCellEditing();
        int selectedRow = table.getSelectedRow();
        boolean modify = false;
        for (int i = 0; i < classItems.size(); i++) {
            String classItem = classItems.get(i);
            if(classItem.endsWith(".class")) {
                classItem = classItem.substring(0, classItem.length()-6) + ".java";
                classItems.set(i, classItem);
                modify = true;
            }
        }
        if(modify) {
            model.fireTableDataChanged();
            editRowAt(selectedRow);
        }
    }

    private void cmdToClass() {
        if(classItems.size() <= 0) {
            return;
        }

        stopCellEditing();
        int selectedRow = table.getSelectedRow();
        boolean modify = false;
        for (int i = 0; i < classItems.size(); i++) {
            String classItem = classItems.get(i);
            if(classItem.endsWith(".java")) {
                classItem = classItem.substring(0, classItem.length()-5) + ".class";
                classItems.set(i, classItem);
                modify = true;
            }
        }
        if(modify) {
            model.fireTableDataChanged();
            editRowAt(selectedRow);
        }
    }

    private void cmdLineUp() {
        stopCellEditing();
        model.moveUp();
    }

    private void cmdLineDown() {
        stopCellEditing();
        model.moveDown();
    }

    private void cmdLineTop() {
        stopCellEditing();
        model.moveTop();
    }

    private void cmdLineBottom() {
        stopCellEditing();
        model.moveBottom();
    }

    private void cmdLineAdd() {
        stopCellEditing();
//        addLine(classItems.size()-1);
        addLine(table.getSelectedRow());
    }

    private void cmdLineDel() {
        stopCellEditing();
        delLine(table.getSelectedRow());
    }

    private void cmdLineClear() {
        stopCellEditing();
        classItems.clear();
        classItems.add("");
        model.fireTableDataChanged();
        editRowAt(0);
    }

    private void addInner() {
        stopCellEditing();

        //记录当前行
        String current = "";
        int index = table.getSelectedRow();
        if(index >= 0 && index < classItems.size()) {
            current = classItems.get(index);
        }

        File classPathDir = checkClassPath();
        String classPath = classPathDir.getAbsolutePath();

        LinkedList<String> tmps = new LinkedList<String>();
        for(String classItem : classItems) {
            tmps.add(classItem);
            if(!classItem.endsWith(".class")) {
                continue;
            }
            File fClassFile = FileUtils.getFile(classPathDir, classItem);
            if(!fClassFile.exists() || !fClassFile.isFile() || fClassFile.getName().contains("$")) {
                continue;
            }

            File fPackageDir = fClassFile.getParentFile();
            if(fPackageDir == null) {
                continue;
            }
            File[] files = fPackageDir.listFiles();
            if (files == null) {
                continue;
            }

            String mpath = fClassFile.getAbsolutePath();
            String prefix = mpath.substring(0, mpath.length()-6) + "$";
            int len = classPath.length() + File.separator.length();
            for (File aFile : files) {
                if(aFile.isFile()) {
                    String path = aFile.getAbsolutePath();
                    if(path.endsWith(".class") && path.startsWith(prefix)) {
                        path = path.substring(len);
                        if(!classItems.contains(path) && !tmps.contains(path)) {
                            tmps.add(path);
                        }
                    }
                }
            }
        }

        classItems.clear();
        classItems.addAll(tmps);
        model.fireTableDataChanged();

        //使焦点回到当前行
        if(classItems.size() > 0) {
            index = 0;
            if(current != null) {
                for(int i = 0; i < classItems.size(); i++) {
                    if(current.equals(classItems.get(i))) {
                        index = i;
                        break;
                    }
                }
            }

            table.setRowSelectionInterval(index, index);
            editRowAt(index);
        }
    }

    private void delInner() {
        stopCellEditing();

        //记录当前行
        String current = "";
        int index = table.getSelectedRow();
        if(index >= 0 && index < classItems.size()) {
            current = classItems.get(index);
        }

        File classPathDir = checkClassPath();
        for(int i = classItems.size() - 1; i >= 0; i--) {
            String classItem = classItems.get(i);
            if(!classItem.endsWith(".class")) {
                continue;
            }
            File fClassFile = FileUtils.getFile(classPathDir, classItem);
            if(fClassFile.isFile() && fClassFile.getName().contains("$")) {
                classItems.remove(i);
            }
        }

        model.fireTableDataChanged();

        //使焦点回到当前行
        if(classItems.size() > 0) {
            index = 0;
            if(current != null) {
                for(int i = 0; i < classItems.size(); i++) {
                    if(current.equals(classItems.get(i))) {
                        index = i;
                        break;
                    }
                }
            }

            table.setRowSelectionInterval(index, index);
            editRowAt(index);
        }
    }

    private void clearRepeat() {
        stopCellEditing();

        String current = "";
        int index = table.getSelectedRow();
        if(index >= 0 && index < classItems.size()) {
            current = classItems.get(index);
        }

        LinkedList<String> tmps = new LinkedList<String>();
        for(String classItem : classItems) {
            if(tmps.contains(classItem)) {
                continue;
            }
            tmps.add(classItem);
        }
        classItems.clear();
        classItems.addAll(tmps);
        model.fireTableDataChanged();

        if(classItems.size() > 0) {
            index = 0;
            if(current != null) {
                for(int i = 0; i < classItems.size(); i++) {
                    if(current.equals(classItems.get(i))) {
                        index = i;
                        break;
                    }
                }
            }

            table.setRowSelectionInterval(index, index);
            editRowAt(index);
        }
    }

    class FocusAfter implements Runnable {
        private JComponent component;

        public FocusAfter(JComponent component) {
            this.component = component;
        }

        public void run() {
            component.requestFocus();
            component.putClientProperty("hasError", true);
            component.repaint();
        }
    }

    class EditRowAfter implements Runnable {
        private int row;

        public EditRowAfter(int row) {
            this.row = row;
        }

        public void run() {
            editRowAt2(row);
        }
    }

    private File checkClassPath() {
        String classPath = tfClassPath.getText();
        if (classPath == null || classPath.trim().length() == 0) {
            UIUtils.abort("类路径没有设置！", new FocusAfter(tfClassPath));
        }
        classPath = classPath.trim();
        File classPathDir = new File(classPath);
        if (classPath.endsWith(":") || !classPathDir.isDirectory()) {
            UIUtils.abort("类路径设置有误！", new FocusAfter(tfClassPath));
        }
        return classPathDir;
    }

    private File checkOutput() {
        File defaultOutputFile = new File("jar");
        if(!defaultOutputFile.exists()) {
            defaultOutputFile.mkdir();
        }

        String output = tfOutput.getText();
        if (output == null || output.trim().length() == 0) {
            UIUtils.abort("输出路径没有设置！", new FocusAfter(tfOutput));
        }
        output = output.trim();

        File outputFile = new File(output);
        if(!FileUtils.isValidFileName(outputFile.getName())) {
            String name = outputFile.getName();
            if(name.length() <= 0) {
                name = output;
            }
            UIUtils.abort("[" + name + "]不是一个有效的文件名！", new FocusAfter(tfOutput));
        }

        if(!outputFile.getPath().equals(outputFile.getAbsolutePath())) {
            outputFile = new File("jar" + File.separator + outputFile.getPath());
        }
        if(outputFile.isDirectory()) {
            UIUtils.abort(outputFile.getAbsolutePath()+ "：是一个目录！", new FocusAfter(tfOutput));
        }

        File parent = outputFile.getParentFile();
        if (parent == null) {
            UIUtils.abort("输出路径设置有误！", new FocusAfter(tfOutput));
        }

        if (!parent.exists()) {
            UIUtils.abort(parent.getAbsolutePath()+ "：目录不存在！", new FocusAfter(tfOutput));
        }

        return outputFile;
    }

    private File checkManifest() {
        String manifest = tfManifest.getText();
        if (manifest != null && manifest.trim().length() > 0) {
            File manifestFile = new File(manifest.trim());
            if(!manifestFile.getPath().equals(manifestFile.getAbsolutePath())) {
                manifestFile = new File("jar" + File.separator + manifestFile.getPath());
            }
            if (!manifestFile.exists() || manifestFile.isDirectory()) {
                UIUtils.abort("manifest设置有误！", new FocusAfter(tfManifest));
            }
            return manifestFile;
        }
        return null;
    }

    private void checkClassItem() {
        stopCellEditing();
        String classPath = new File(tfClassPath.getText().trim()).getAbsolutePath();
        ArrayList<String> cis = new ArrayList<String>(classItems.size());
        for (int i = 0; i < classItems.size(); i++) {
            String classItem = classItems.get(i);
            File classItemFile = new File(classPath + File.separator + classItem);
            if(classItem.startsWith(File.separator) || classItem.startsWith("/") || !classItemFile.exists()) {
                UIUtils.abort("类选择有误！", new EditRowAfter(i));
            }
            else if(cis.contains(classItem)) {
                UIUtils.abort("存在重复！", new EditRowAfter(i));
            }
            else {
                cis.add(classItem);
            }
        }
    }

    private void checkScheme() {
        checkClassPath();
        checkManifest();
        checkOutput();
        checkClassItem();
    }

    private void showAdvOption(boolean show) {
        boxManifest.setVisible(show);
        boxMainclass.setVisible(show);
        boxNote.setVisible(show);
        spNote.setVisible(show);
    }

    private String getDefaultOutputDir() {
        if(scheme != null) {
            return UIUtils.getCategoryDir(scheme.getCategory().getId());
        }
        return "";
    }

    private void explorerFile(File file, boolean select) {
        if(file != null) {
            try {
//                Runtime.getRuntime().exec("cmd /c start " + file.getAbsolutePath());
                String command = "explorer ";
                if(select) {
                    command += "/select, ";
                }
                command += file.getAbsolutePath();
                Runtime.getRuntime().exec(command);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    private void btnBuildActionPerformed() {
        stopCellEditing();
        checkScheme();

        File classPathDir = new File(tfClassPath.getText().trim());
        String classPath = classPathDir.getAbsolutePath();

        File outputFile = new File(tfOutput.getText().trim());
        if(!outputFile.getPath().equals(outputFile.getAbsolutePath())) {
            outputFile = new File("jar" + File.separator + outputFile.getPath());
        }
        if (outputFile.exists()) {
            int result = JOptionPane.showConfirmDialog(
                    getTopLevelAncestor(), "输出文件己经存在，是否覆盖？", null, JOptionPane.OK_CANCEL_OPTION);
            if (result != JOptionPane.OK_OPTION) {
                tfOutput.requestFocus();
                return;
            }

            FileUtils.deleteDir(outputFile);
        }

        File fTmpDir = new File("tmp");
        if (fTmpDir.exists()) {
            FileUtils.deleteDir(fTmpDir);
        }
        fTmpDir.mkdir();

        //**********************************************************************
        File manifestFile = checkManifest();

        if (manifestFile == null) {
            String mainclass = tfMainClass.getText();
            if (mainclass != null) {
                mainclass = mainclass.trim();
                if (mainclass.length() > 0) {
                    java.util.List<String> lines = new ArrayList<String>();
                    lines.add("Manifest-Version: 1.0");
                    lines.add("Created-By: BuildJar");
                    lines.add("Main-Class: " + mainclass);
                    FileUtils.saveFile(lines, "tmp" + File.separator + "MANIFEST.MF");
                    manifestFile = new File("tmp" + File.separator + "MANIFEST.MF");
                }
            }
        }

        String sTmpClassesDir = "tmp" + File.separator + "classes";
        File fTmpClassesDir = new File(sTmpClassesDir);
        if (!fTmpClassesDir.exists()) {
            fTmpClassesDir.mkdir();
        }

        //生成说明
        if(cbOpNote.isSelected()) {
            String note = tpNote.getText();
            if(note.length() > 0) {
                FileUtils.saveFile(note, sTmpClassesDir + File.separator + "readme.txt");
            }
        }

        //复制文件
        for (String sClassFile : classItems) {
            File fClassFile = FileUtils.getFile(classPathDir, sClassFile);
            if (!fClassFile.getPath().startsWith(classPath)) {
                continue;
            }

            if (fClassFile.isFile()) {
                File fTmpClassFileDir = new File(sTmpClassesDir + fClassFile.getParent().substring(classPath.length()));
                File fTmpClassFile = new File(sTmpClassesDir + fClassFile.getPath().substring(classPath.length()));

                fTmpClassFileDir.mkdirs();
                try {
                    FileUtils.copyFile(fClassFile, fTmpClassFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else if (fClassFile.isDirectory()) {
                File fTmpClassFileDir;
                File fTmpClassFile;
                if (fClassFile.getPath().equals(classPath)) {
                    fTmpClassFile = new File(sTmpClassesDir);
                } else {
                    fTmpClassFileDir = new File(sTmpClassesDir + fClassFile.getParent().substring(classPath.length()));
                    fTmpClassFileDir.mkdirs();
                    fTmpClassFile = new File(sTmpClassesDir + fClassFile.getPath().substring(classPath.length()));
                }

                try {
                    FileUtils.copyDirectiory(fClassFile.getPath(), fTmpClassFile.getPath());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //生成jar
        StringBuffer cmd = new StringBuffer();
        cmd.append("cmd.exe /c start ");
        cmd.append("jar -cvf");
        if(manifestFile != null) {
            cmd.append("m ");
        }
        else {
            cmd.append(" ");
        }
        cmd.append("\"" + outputFile.getAbsolutePath() + "\" ");
        if(manifestFile != null) {
            cmd.append("\"" + manifestFile.getAbsolutePath() + "\" ");
        }
        cmd.append("-C ");
        cmd. append ("\"" + fTmpClassesDir.getAbsolutePath () + "\" ");
        cmd.append(". ");

        Runtime run = Runtime.getRuntime();
        try {
            Process p = run. exec (cmd. toString ());// 启动另一个进程来执行命令
            BufferedInputStream in = new BufferedInputStream(p.getInputStream());
            BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
            String lineStr;
            while ( (lineStr = inBr.readLine()) != null)
                //获得命令执行后在控制台的输出信息
                System.out.println(lineStr) ;// 打印输出信息

            //检查命令是否执行失败。
            if (p.waitFor() != 0) {
                if(p.exitValue() == 1)//p.exitValue()==0表示正常结束，1:非正常结束
                System.err.println("命令执行失败！");
            }
            inBr.close ();
            in.close ();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

//        System.out.println(UUID.randomUUID());
    }
}
